mixin validatorRow(validator, params)
  tbody
    tr.table__tr
      td.table__td: kbd=validator
      if params
        td.table__td=(Array.isArray(params) ? params.join(', ') : params)
      else
        td.table__td: em none
      td.table__td
        block

+section('Validators')
  p.typo__p
    | <em>vuelidate</em> comes with a set of builtin validators that you
    | can just require and use, but it doesn't end there. All of those are just
    | simple predicates - functions of data into <kbd>boolean</kbd>, which denotes
    | if data is valid. You can easily write your own
    | or use any function in this shape from any library you already have, like
    | <kbd>_.conformsTo</kbd> from <em>lodash</em> or higher order functions
    | and chains like <kbd>R.cond</kbd> from <em>ramda</em>.
    | Think of the possibilities.
  p.typo__p
    | This documentation presents every builtin validator with short description
    | and presents an example custom validator implementation
    | to help understanding them and writing your own as easy as possible.
  +subsection('Builtin validators')
    p.typo__p
      | To use any of builtin validators, you have to import it from vuelidate library.
    pre(v-pre).language-javascript
      code.
        import { required, maxLength } from 'vuelidate/lib/validators'
    p.typo__p
      | You can also import specific validators directly, to avoid loading
      | unused ones in case your bundler doesn't support tree shaking.
      | This is not required for Rollup or Webpack 2 among others.
    pre(v-pre).language-javascript
      code.
        import required from 'vuelidate/lib/validators/required'
        import maxLength from 'vuelidate/lib/validators/maxLength'
    p.typo__p
      | It is possible to use validators directly in browser by using a browser-ready bundle.
      | Keep in mind this will always load all builtin validators at once.
    pre(v-pre).language-html
      code='<script src="vuelidate/dist/validators.min.js"></script>'
    pre(v-pre).language-javascript
      code.
        var required = validators.required
        var maxLength = validators.maxLength
    p.typo__p
      | Here is a full list of provided validators.
      .table__container
        table.table.table--full-size.table--fixed
          thead
            tr.table__tr
              th.table__th(width="160") Name
              th.table__th(width="120") Meta parameters
              th.table__th Description
          tbody
            +validatorRow('required')
              | Requires non-empty data.
              | Checks for empty arrays and strings containing only whitespaces.
            +validatorRow('requiredIf', ['locator *'])
              | Requires non-empty data only if provided property or predicate is true.
            +validatorRow('requiredUnless', ['locator *'])
              | Requires non-empty data only if provided property or predicate is false.
            +validatorRow('minLength', ['min length'])
              | Requires the input to have a minimum specified length, inclusive. Works with arrays.
            +validatorRow('maxLength', ['max length'])
              | Requires the input to have a maximum specified length, inclusive. Works with arrays.
            +validatorRow('minValue', ['min'])
              | Requires entry to have a specified minimum numeric value or Date.
            +validatorRow('maxValue', ['max'])
              | Requires entry to have a specified maximum numeric value or Date.
            +validatorRow('between', ['min, max'])
              | Checks if a number or Date is in specified bounds. Min and max are both inclusive.
            +validatorRow('alpha')
              | Accepts only alphabet characters.
            +validatorRow('alphaNum')
              | Accepts only alphanumerics.
            +validatorRow('numeric')
              | Accepts only numerics.
            +validatorRow('integer')
              | Accepts positive and negative integers.
            +validatorRow('decimal')
              | Accepts positive and negative decimal numbers.
            +validatorRow('email')
              | Accepts valid email addresses. Keep in mind you still have to carefully verify it on your server,
              | as it is impossible to tell if the address is real without sending verification email.
            +validatorRow('ipAddress')
              | Accepts valid IPv4 addresses in dotted decimal notation like <em>127.0.0.1</em>.
            +validatorRow('macAddress', [ 'separator\=\':\'' ])
              | Accepts valid MAC addresses like <em>00:ff:11:22:33:44:55</em>. Don't forget to call it <kbd>macAddress()</kbd>, as it has optional parameter.
              | You can specify your own separator instead of <kbd>':'</kbd>.
              | Provide empty separator <kbd>macAddress('')</kbd> to validate MAC addresses like <em>00ff1122334455</em>.
            +validatorRow('sameAs', ['locator *'])
              | Checks for equality with a given property.
            +validatorRow('url')
              | Accepts only URLs.
            +validatorRow('or', ['validators...'])
              | Passes when at least one of provided validators passes.
            +validatorRow('and', ['validators...'])
              | Passes when all of provided validators passes.
            +validatorRow('not', ['validator'])
              | Passes when provided validator would not pass, fails otherwise. Can be chained with other validators like <kbd>not(sameAs('field'))</kbd>.
            +validatorRow('withParams', ['$params', 'validator'])
              | Not really a validator, but a validator modifier. Adds a <kbd>$params</kbd> object to the
              | provided validator. Can be used on validation functions or even entire nested
              | field validation objects. Useful for creating your own custom validators.
    p.typo__p
      | * Locator can be either a sibling property name or a function.
      | When provided as a function, it receives the model under validation as argument and
      | <kbd>this</kbd> is bound to the component instance so you can access all its
      | properties and methods, even in the scope of a nested validation.
    p.typo__p
      | Example of conditional validations using a locator meta parameter:
      pre(v-pre).language-javascript
        code.
          export default {
            ...,
            data() {
              return {
                field: "foo",
                nested: {
                  field: "bar",
                  someFlag: true
                }
              }
            },
            computed: {
              isOptional() {
                return true // some conditional logic here...
              }
            },
            validations: {
              field: {
                required: requiredUnless('isOptional')
              },
              nested: {
                required: requiredIf(function (nestedModel) {
                  return !this.isOptional && nestedModel.someFlag
                })
              }
            }
          }

  +subsection('Validator parameters')
    p.typo__p
      | Every validator can save parameters. Validators are responsible for saving their type
      | and parameters, because they are simple functions, and we may want to inform the user about
      | them.
    p.typo__p
      | Use <kbd>withParams</kbd> to apply parameters to a validator. Declared parameters bubble up
      | by one level, so they are included in the <kbd>$params</kbd> of the parent validation object.
      | Vuelidate is designed in a way that does not allow the validation result to directly include
      | params.
    p.typo__p
      | You may call the <kbd>$flattenParams</kbd> method on a validation object to get an array of validator
      | params for all validators that exist in that validation object. For example, let's say
      | a validation object contains a <kbd>between</kbd> validator to check that a value is between
      | 5 and 10. Calling <kbd>$flattenParams</kbd> returns the following array.
    code
      | [{ path: [], name: 'between', params: { type: 'between', min: 5, max: 10 } }]

+section('Custom Validators')
  p.typo__p
    | You can easily write custom validators and combine them with builtin ones,
    | as those are just a simple predicate functions.
  +subsection('Simplest example')
    p.typo__p
      | Suppose you want a validator that checks if strings contains <em>cool</em> substring in it.
      | The way to approach this is to use normal javascript function that checks that.
    pre(v-pre).language-javascript
      code.
        const mustBeCool = (value) => value.indexOf('cool') >= 0

    p.typo__p
      | The second part is actually applying your validator. You can do it exactly the same way as with builtin ones.
    pre(v-pre).language-javascript
      code.
        validations: {
          myField: {
            required,
            mustBeCool
          }
        }

  +subsection('Optional validator')
    p.typo__p
      | Pattern presented above is often good enough, but this validator will always return <kbd>false</kbd> for empty input.
      | This is not correct when your input is considered optional. For this reason, there exist a <kbd>req</kbd> helper,
      | which is kinda strippe-down version of required validator. You can use it to make your validator
      | behave well in presense of optional fields, that is the ones without <kbd>required</kbd> validator.
    pre(v-pre).language-javascript
      code.
        import { helpers } from 'vuelidate/lib/validators'
        const mustBeCool = (value) => !helpers.req(value) || value.indexOf('cool') >= 0

        // ...

        validations: {
          myField: {
            mustBeCool
          }
        }

  +subsection('Extra parameters')
    p.typo__p
      | If your validator needs to provide parameters, you can simply create a
      | higher order function that returns the actual validator, like in <kbd>between</kbd> builtin validator.
    pre(v-pre).language-javascript
      code.
        import { helpers } from 'vuelidate/lib/validators'
        const contains = (param) =>
          (value) => !helpers.req(value) || value.indexOf(param) >= 0

        // ...

        validations: {
          myField: {
            mustBeCool: contains('cool')
          }
        }

  +subsection('$props support')
    p.typo__p
      | This is all fine if you are not using the feature of <kbd>$props</kbd> property, for example in your translation system.
      | To make your validator also generate some useful <kbd>$props</kbd>, you can use <kbd>withParams</kbd> helper.
      | The easiest case is to simply add <kbd>type</kbd> metadata, which might be useful in choosing
      | correct translation string later on.
    pre(v-pre).language-javascript
      code.
        import { helpers } from 'vuelidate/lib/validators'
        const mustBeCool = helpers.withParams(
          { type: 'mustBeCool' },
          (value) => !helpers.req(value) || value.indexOf('cool') >= 0
        )

        // ...

        console.log(this.$v.myField.$params.mustBeCool)
        // -> { type: 'mustBeCool' }

    p.typo__p
      | The same behaviour extends to higher order validators, ones with extra parameters. You just must be careful to
      | wrap the <strong>inner</strong> function with <kbd>withParams</kbd> call, as follows.
    pre(v-pre).language-javascript
      code.
        import { helpers } from 'vuelidate/lib/validators'
        const contains = (param) =>
          helpers.withParams(
            { type: 'contains', value: param },
            (value) => !helpers.req(value) || value.indexOf(param) >= 0
          )

        // ...
        validations: {
          myField: {
            mustBeCool: contains('cool')
          }
        }

        // ...
        console.log(this.$v.myField.$params.mustBeCool)
        // -> { type: 'contains', value: 'cool' }


  +subsection('accessing component')
    p.typo__p
      | In more complex cases when access to the whole model is necessary, like <kbd>sameAs</kbd>,
      | make use of the function context (<kbd>this</kbd>) to access any value on your component
      | or use provided <kbd>parentVm</kbd> to access sibling properties.
    pre(v-pre).language-javascript
      code.
        // both equivalent
        const otherFieldContainsMe =
          (value, vm) => vm.other.nested.field.contains(value)

        function otherFieldContainsMe (value) {
          return this.other.nested.field.contains(value)
        }

  +subsection('regex based validator')
    p.typo__p
      | Some validators can be easily expressed as regex. You can use a <kbd>regex</kbd> helper to quickly define full-fledged validator of this kind.
      | This already includes handling optional fields and <kbd>$params</kbd>.
    pre(v-pre).language-javascript
      code.
        import { helpers } from 'vuelidate/lib/validators'
        const alpha = helpers.regex('alpha', /^[a-zA-Z]*$/)

  +subsection('locator based validator')
    p.typo__p
      | If you want to use locator strategy, exactly the same one as in <kbd>sameAs</kbd> or <kbd>requiredIf</kbd>
      | builtin validators, you can use <kbd>ref</kbd> helper to accomplish that, in exactly the same way
      | how it is used inside those two validators.
    +validatorCode('sameAs')
    +validatorCode('requiredIf')
    p.typo__p
      | Note that imports are slightly different, as this is how the code looks like from library source point of view.
      | This style is the correct one if you are willing to <a href="https://github.com/monterail/vuelidate#fork-destination-box">contribute your own validators to vuelidate</a>.
      | You should still use <kbd>helpers</kbd> export inside your own code (as presented in previous examples).

  +subsection('List of helpers')
    p.typo__p
      | This table contains all helpers that can be used to help you with writing your own validators.
      | You can import them from validators library
    pre(v-pre).language-javascript
      code.
        import { helpers } from 'vuelidate/lib/validators'

    .table__container
      table.table.table--full-size.table--fixed
        thead
          tr.table__tr
            th.table__th(width="130") Helper
            th.table__th Description
        tbody
          tr.table__tr
            td.table__td: kbd withParams
            td.table__td
              | Allows adding <kbd>$params</kbd> metadata to your validation function.
          tr.table__tr
            td.table__td: kbd req
            td.table__td
              | Minimal version of <kbd>required</kbd> validator. Use it to make your validator accept optional fields
          tr.table__tr
            td.table__td: kbd ref
            td.table__td
              | A locator helper. This allows for convinient referencing of other fields in the model.
          tr.table__tr
            td.table__td: kbd len
            td.table__td
              | Get length of any kind value, whatever makes sense in the context. This can mean array length,
              | string length, or number of keys on the object
          tr.table__tr
            td.table__td: kbd regex
            td.table__td
              | Useful for quick creation of regex based validators.
